package net.lym.javamind.javadatetime;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * Java 日期时间 工具类
 */
public class JavaDateTimeUtil {

    /**
     * 获取两个字符串日期之间的所有年月(yyyy-MM)
     *
     * @param startDateStr 开始日期(yyyy-MM)字符串
     * @param endDateStr   结束日期(yyyy-MM)字符串
     * @return 一个包含所有年月的列表，格式为YYYY-MM
     */
    public static List<String> getMonthBetweenDateStr(String startDateStr, String endDateStr){
        // 声明简单日期格式化对象
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        // 声明保存日期集合
        List<String> list = new ArrayList<>();
        try {
            // 转化成日期类型
            Date startDate = sdf.parse(startDateStr);
            Date endDate = sdf.parse(endDateStr);

            // 使用Calendar进行日期比较判断
            Calendar calendar = Calendar.getInstance();
            // 当开始日期小于等于结束日期时循环
            while (startDate.getTime() <= endDate.getTime()){
                // 把日期添加到集合
                list.add(sdf.format(startDate));
                // 设置日期
                calendar.setTime(startDate);
                // 把月份增加一个单位
                calendar.add(Calendar.MONTH, 1);
                // 获取增加后的日期
                startDate = calendar.getTime();
            }
        } catch (ParseException e) {
            // 打印异常信息
            e.printStackTrace();
        }
        // 返回日期列表
        return list;
    }

    /**
     * getMonthBetweenDateStr() 方法
     * 1、潜在问题及风险
     *  1.日期格式化和解析的安全性问题：
     *  - SimpleDateFormat 不是线程安全的。如果该方法在多线程环境中使用，可能会导致不可预测的行为。
     *  2.异常处理不够完善：
     *  - 目前只捕获了 ParseException 并打印堆栈跟踪信息，但没有对异常进行更详细的处理或返回有意义的结果。
     *  3.边界条件处理：
     *  - 如果 startDateStr 和 endDateStr 是相同的月份，代码会正确处理吗？需要确保这种情况下也能正常工作。
     *  - 如果输入的日期格式不正确，应该有更友好的错误提示。
     *  4.性能问题：
     *  - 每次循环中都创建新的 Calendar 实例并设置时间，这会导致不必要的开销。
     *  5.代码可读性和维护性：
     *  - 变量命名可以更具描述性，例如 currentDate 代替 startDate，以避免混淆。
     *  - 方法注释可以更详细，说明参数和返回值的具体要求。
     * 2、优化建议
     *  1.使用线程安全的日期处理工具：
     *  - 使用 java.time 包中的 YearMonth 类来替代 SimpleDateFormat 和 Calendar，提高代码的线程安全性和可读性。
     *  2.改进异常处理：
     *  - 抛出自定义异常或返回空列表，并提供更有意义的错误信息。
     *  3.处理边界条件：
     *  - 确保相同月份的情况能正确处理。
     *  4.优化性能：
     *  - 避免在循环中重复创建 Calendar 实例。
     *  5.增强代码可读性和维护性：
     *  - 改进变量命名和注释。
     */

    /**
     * 获取两个字符串日期之间的所有年月(yyyy-MM)
     *
     * @param startDateStr 开始日期(yyyy-MM)字符串
     * @param endDateStr   结束日期(yyyy-MM)字符串
     * @return 一个包含所有年月的列表，格式为YYYY-MM
     * @throws IllegalArgumentException 如果日期格式不正确或结束日期早于开始日期
     */
    public static List<String> getMonthBetweenDateStrPlus(String startDateStr, String endDateStr) {
        // 声明日期格式化对象
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");

        try {
            YearMonth startMonth = YearMonth.parse(startDateStr, formatter);
            YearMonth endMonth = YearMonth.parse(endDateStr, formatter);

            // 检查结束日期是否早于开始日期
            if (startMonth.isAfter(endMonth)) {
                throw new IllegalArgumentException("结束日期不能早于开始日期");
            }

            // 声明保存日期集合
            List<String> list = new ArrayList<>();
            YearMonth currentMonth = startMonth;

            while (!currentMonth.isAfter(endMonth)) {
                // 把日期添加到集合
                list.add(currentMonth.format(formatter));
                // 增加一个月
                currentMonth = currentMonth.plusMonths(1);
            }

            return list;

        } catch (DateTimeParseException e) {
            throw new IllegalArgumentException("日期格式不正确，请使用 yyyy-MM 格式", e);
        }
    }



}
